/*
 armstorm - ARM/THUMB Disassembler Library

 http://code.google.com/p/armstorm/
 distorm at gmail dot com
 Copyright (C) 2012 Gil Dabah
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#ifndef armstorm_h
#define armstorm_h

#define ARMSTORM_VERSION 0.1

typedef enum {ENDIANITY_BIG, ENDIANITY_LITTLE} _EndianityType;
typedef unsigned long long _AddressType;
typedef enum {OPERAND_NONE, OPERAND_REG, OPERAND_IMM, OPERAND_ADDR, OPERAND_REGLIST} _OperandType;
typedef enum {DECRES_SUCCESS, DECRES_INPUTERR} _DecodeResult;

typedef enum {
    REG_R0 = 0, REG_R1, REG_R2, REG_R3, 
	REG_R4, REG_R5, REG_R6, REG_R7,
    REG_R8, REG_R9, REG_R10, REG_R11,
    REG_R12, REG_SP, REG_LR, REG_PC
} _ARM_REGISTERS;

typedef enum {
	I_UNDEFINED = 0, 

	/* Thumb v1 Instructions */
	I_ADC, I_ADD, I_AND, I_ASR, 
	I_BEQ, I_BNE, I_BCS, I_BCC,
	I_BMI, I_BPL, I_BVS, I_BVC, 
	I_BHI, I_BLS, I_BGE, I_BLT, 
	I_BGT, I_BLE, I_BAL, I_B, 
	I_BIC, I_BL, I_BX, I_CMN, 
	I_CMP, I_EOR, I_LDMIA, I_LDR, 
	I_LDRB, I_LDRH, I_LDRSB, I_LDRSH, 
	I_LSL, I_LSR, I_MOV, I_MUL, 
	I_MVN, I_NEG, I_ORR, I_POP, 
	I_PUSH, I_ROR, I_SBC, I_STMIA,
	I_STR, I_STRB, I_STRH, I_SUB, 
	I_SWI, I_TST, 
	
	/* Thumb v2 Instructions */
	I_BKPT, I_BLX, 
	
	/* Thumb v3 Instructions */
	I_CPS, I_CPY, I_REV, I_REV16, 
	I_REVSH, I_SETEND, I_SXTB, I_SXTH, 
	I_UXTB, I_UXTH 
} _ThumbInstructionType;

typedef struct {
    /* __OUT */ unsigned char type;  /* Type of operand from _OperandType. */
    /* __OUT */ short value;         /* Value of operand according to its type. */
} _Operand;

typedef enum {
	EQ, NE, CS, CC, MI, PL, VS, VC,
	HI, LS, GE, LT, GT, LE, AL, INVALID
} _Condition;
#define COND_BIT_POS   (28)
#define COND_BIT_MASK  (0xF0000000)

/* Flags type for an instruction. */
typedef unsigned short _iflags;

/* Instruction wasn't found or has an invalid operand. */
#define FLAG_INVALID    (0x1)
/* One of the load or store instructions. */
#define FLAG_MEMORY     (0x2)
/* The big inst means it's 4 bytes long instruction, otherwise 2. */
#define FLAG_BIG_INST   (0x4)
/* Immediate operand is be sign extended. */
#define FLAG_SIGNED_IMM (0x8)
/* Instruction is a conditional instruction */
#define FLAG_CONDITIONAL (0x10)

typedef struct {
    /* __OUT */ _AddressType   address;     /* Address of current instruction. */
    /* __OUT */ _AddressType   target;      /* Target address of a branch instruction. */
    /* __OUT */ unsigned short opcode;      /* The opcode id in _ThumbOpcodeType. */
    /* __OUT */ _iflags        flags;       /* See flags above. */
    /* __OUT */ _Operand       operands[3]; /* Up to three operands of struct _Operand. */
	/* __OUT */ _Condition     cond;        /* Condition of the instruction - Only valid when FLAG_CONDITIONAL 
	                                           is set. Signified the instruction contains conditional flags */
} _DInst;

typedef struct {
    /* __IN */ _AddressType         address;         /* An ODD ADDRESS will cause to decode THUMB instructions! */
    /* __IN */ const unsigned char* code;            /* Pointer to code bytes. (Should be aligned to 2/4). */
    /* __IN */ unsigned int         codeLength;      /* Must be even, a multiple of 2/4 depends on mode. */
    /* __IN */ _EndianityType       endianity;       /* Decode instructions in big/little endian. */
    /* __IN */ unsigned int         maxInstructions; /* Number of instructions that can be written to 'instructions'. */

    /* __OUT */ _DInst*      instructions ;            /* Decoded instructions are written to 'instructions'. */
    /* __OUT */ unsigned int decodedInstructionsCount;  /* Number of decoded instructions. */
} _DecomposeInfo;

#define GET_REGISTER_NAME(r) ((const char*)_REGISTERS[(r)])
extern char* _REGISTERS[];

#define GET_MNEMONIC_SIZE(m) ((const unsigned char)(_THUMB_MNEMONICS[m][0]))
#define GET_MNEMONIC_NAME(m) ((const char*)(&(_THUMB_MNEMONICS[m][1])))
extern const unsigned char * _THUMB_MNEMONICS[];

#define GET_CONDITION_NAME(m) ((const char*)_ARM_CONDITIONS[(m)])
extern const char * _ARM_CONDITIONS[];

extern _DecodeResult armstorm_decompose(_DecomposeInfo* info);

typedef struct {
    _AddressType address;
    unsigned char size;
    char hex[11];
    char instruction[40];
} _TInst;

extern void armstorm_format(const _DecomposeInfo* ci, const _DInst* inst, _TInst* text);

#endif /* armstorm_h */
